TypeScript 2.3以后的版本支持使用--checkJs.js文件进行类型检查并提示错误的模式。

你可以通过添加// @ts-nocheck注释来忽略类型检查;相反你可以通过去掉--checkJs设置并添加// @ts-check注释来选则检查某些.js文件。
你还可以使用// @ts-ignore来忽略本行的错误。

下面是一些值得注意的类型检查在.js文件与.ts文件上的差异:

在JSDoc上使用类型

.js文件里,类型可以和在.ts文件里一样被推断出来。
同样地,当类型不能被推断时,它们可以通过JSDoc来指定,就好比在.ts文件里那样。

JSDoc注解修饰的声明会被设置为这个声明的类型。比如:

  1. /** @type {number} */
  2. var x;
  3. x = 0; // OK
  4. x = false; // Error: boolean is not assignable to number

你可以在这里找到所有JSDoc支持的模式,JSDoc文档

从类内部赋值语句推断属性声明

ES2015/ES6不存在类属性的声明。属性是动态的赋予的,就如同对象字面量一样。

.js文件里,属性声明是由类内部的属性赋值语句推断出来的。属性的类型是赋值语句右侧所有值的联合。构造函数里定义的属性是永远存在的,在方法存取器里定义的被认为是可选的。

使用JSDoc修饰属性赋值来指定属性类型。例如:

  1. class C {
  2. constructor() {
  3. /** @type {number | undefined} */
  4. this.prop = undefined;
  5. }
  6. }
  7. let c = new C();
  8. c.prop = 0; // OK
  9. c.prop = "string"; // Error: string is not assignable to number|undefined

如果属性永远都不在类的内部被设置,那么它们被当成是未知的。如果类具有只读的属性,考虑在构造函数里给它初始化成undefined,例如this.prop = undefined;

CommonJS模块输入支持

.js文件支持将CommonJS模块做为输入模块格式。对exportsmodule.exports的赋值被识别为导出声明。
相似地,require函数调用被识别为模块导入。例如:

  1. // import module "fs"
  2. const fs = require("fs");
  3. // export function readFile
  4. module.exports.readFile = function(f) {
  5. return fs.readFileSync(f);
  6. }

对象字面量是开放的

默认地,变量声明中的对象字面量本身就提供了类型声明。新的成员不能被加到对象中去。
这个规则在.js文件里被放宽了;对象字面量具有开放的类型,允许添加并访问原先没有定义的属性。例如:

  1. var obj = { a: 1 };
  2. obj.b = 2; // Allowed

对象字面量具有默认的索引签名[x:string]: any,它们可以被当成开放的映射而不是封闭的对象。

与其它JS检查行为相似,这种行为可以通过指定JSDoc类型来改变,例如:

  1. /** @type {{a: number}} */
  2. var obj = { a: 1 };
  3. obj.b = 2; // Error, type {a: number} does not have property b

函数参数是默认可选的

由于JS不支持指定可选参数(不指定一个默认值),.js文件里所有函数参数都被当做可选的。使用比预期少的参数调用函数是允许的。

需要注意的一点是,使用过多的参数调用函数会得到一个错误。

例如:

  1. function bar(a, b){
  2. console.log(a + " " + b);
  3. }
  4. bar(1); // OK, second argument considered optional
  5. bar(1, 2);
  6. bar(1, 2, 3); // Error, too many arguments

使用JSDoc注解的函数会被从这条规则里移除。使用JSDoc可选参数语法来表示可选性。比如:

  1. /**
  2. * @param {string} [somebody] - Somebody's name.
  3. */
  4. function sayHello(somebody) {
  5. if (!somebody) {
  6. somebody = 'John Doe';
  7. }
  8. alert('Hello ' + somebody);
  9. }
  10. sayHello();

arguments推断出的var-args参数声明

如果一个函数的函数体内有对arguments的引用,那么这个函数会隐式地被认为具有一个var-arg参数(比如:(...arg: any[]) => any))。使用JSDoc的var-arg语法来指定arguments的类型。

未指定的类型参数默认为any

未指定的泛型参数类型将默认为any。有如下几种情形:

在extends语句中

例如,React.Component被定义成具有两个泛型参数,PropsState
在一个.js文件里,没有一个合法的方式在extends语句里指定它们。默认地参数类型为any

  1. import { Component } from "react";
  2. class MyComponent extends Component {
  3. render() {
  4. this.props.b; // Allowed, since this.props is of type any
  5. }
  6. }

使用JSDoc的@augments来明确地指定类型。例如:

  1. import { Component } from "react";
  2. /**
  3. * @augments {Component<{a: number}, State>}
  4. */
  5. class MyComponent extends Component {
  6. render() {
  7. this.props.b; // Error: b does not exist on {a:number}
  8. }
  9. }

在JSDoc引用中

JSDoc里未指定的泛型参数默认为any

  1. /** @type{Array} */
  2. var x = [];
  3. x.push(1); // OK
  4. x.push("string"); // OK, x is of type Array<any>
  5. /** @type{Array.<number>} */
  6. var y = [];
  7. y.push(1); // OK
  8. y.push("string"); // Error, string is not assignable to number

在函数调用中

泛型函数的调用使用arguments来推断泛型参数。有时候,这个流程不能够推断出类型,大多是因为缺少推断的源;在这种情况下,泛型参数类型默认为any。例如:

  1. var p = new Promise((resolve, reject) => { reject() });
  2. p; // Promise<any>;